package com.zoro.barn.commons.db.autopage;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.zoro.barn.commons.tools.json.JsonUtil;
import com.zoro.barn.commons.tools.string.StringTools;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;


import java.io.IOException;
import java.io.InputStream;

/**
 * 分布参数过滤器会在请求的 search或者 body中查找分布参数，并保存在线程变量中在自动分页sql拦截时可以使用
 *
 * @author zhaoxingwu
 */
@Order(Integer.MIN_VALUE + 200)
public class PageParamFilter implements Filter {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final static ThreadLocal<Integer> PAGE_SIZE = new ThreadLocal<>();
    private final static ThreadLocal<Integer> CURRENT = new ThreadLocal<>();

    /**
     * 参数中的key是什么
     */
    private final String currentPageKey;
    private final String pageSizeKey;

    PageParamFilter() {
        currentPageKey = "_current";
        pageSizeKey = "_pageSize";
    }

    PageParamFilter(String currentPageKey, String pageSizeKey) {

        if (currentPageKey == null || currentPageKey.isBlank()) {
            throw new RuntimeException();
        }
        if (pageSizeKey == null || pageSizeKey.isBlank()) {
            throw new RuntimeException();
        }
        this.currentPageKey = currentPageKey;
        this.pageSizeKey = pageSizeKey;
    }


    @Override
    public void init(FilterConfig filterConfig) {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        try {
            this.setPageParam((HttpServletRequest) servletRequest);
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            PAGE_SIZE.remove();
            CURRENT.remove();
        }
    }

    private void setPageParam(HttpServletRequest request) {
        try {
            int current = 0;
            int pageSize = 0;
            String contentType = request.getContentType();
            if (HttpMethod.POST == HttpMethod.valueOf(request.getMethod())) {
                if (StringUtils.contains(contentType, MediaType.APPLICATION_JSON_VALUE)) {

                    InputStream is = request.getInputStream();
                    ObjectNode json = JsonUtil.readJsonObject(is);
                    current = JsonUtil.getInteger(json, this.currentPageKey, 0);
                    pageSize = JsonUtil.getInteger(json, this.pageSizeKey, 0);
                } else if (StringUtils.contains(contentType, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
                    InputStream is = request.getInputStream();
                    ObjectNode json = JsonUtil.readJsonObject(is);
                    current = JsonUtil.getInteger(json, this.currentPageKey, 0);
                    pageSize = JsonUtil.getInteger(json, this.pageSizeKey, 0);
                }  else {
                    if (logger.isWarnEnabled()) {
                        logger.warn("request method {} ,content type {} is not supported.", request.getMethod(),
                                contentType);
                    }
                }
            } else if (HttpMethod.GET == HttpMethod.valueOf(request.getMethod())) {
                String queryString = request.getQueryString();
                String currentStr = StringTools.getParamFromQueryString(queryString, this.currentPageKey);
                String pageSizeStr = StringTools.getParamFromQueryString(queryString, this.pageSizeKey);
                current = currentStr == null ? 0 : Integer.parseInt(currentStr);
                pageSize = pageSizeStr == null ? 0 : Integer.parseInt(pageSizeStr);
            } else {
                if (logger.isWarnEnabled()) {
                    logger.warn("request method {} ,content type {} is not supported.", request.getMethod(),
                            contentType);
                }
            }
            CURRENT.set(current);
            PAGE_SIZE.set(pageSize);


        } catch (IOException e) {
            logger.error(" error occurred when get page parameter from request . ", e);
        }
    }

    public static int pageSize() {
        Integer size = PAGE_SIZE.get();
        return size == null ? 0 : size;
    }

    public static int currentPage() {
        Integer current = CURRENT.get();
        return current == null ? 0 : current;
    }


    @Override
    public void destroy() {

    }
}
